using System;
using NaughtyAttributes;
using SimpleJSON;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace Gj
{
    public class TextHelper : NodeHelper
    {
        public enum UnderlineType
        {
            None,
            Always,
            Exist
        }

        public Color disableColor = new(255, 255, 255, 0.4f);
        public Color originColor = new(255, 255, 255);
        public string disableText;
        public string originText;
        public string localText;
        public string placeholder;
        public bool placeholderOnline;
        public bool pro;
        public bool online;
        public bool auto;
        public bool local;
        public string format;
        public bool formatOnline;
        public bool wrap;
        public UnderlineType underlineType = UnderlineType.None;
        public TextExtend textExtend;
        public AdaptiveSize adaptiveSize;
        public RectTransform rectTransform;

        [SelectRef(UIKey.DATA_KEY)] public SelectKey disabledKey;
        public bool invert;
        private bool _init;
        private Language _language = Language.None;
        private string _s;
        private Text _Text;
        private TextMeshProUGUI _TextPro;
        protected bool disabled;

        private Text Text
        {
            get
            {
                if (_Text == null) _Text = GetComponent<Text>();
                return _Text;
            }
        }

        private TextMeshProUGUI TextPro
        {
            get
            {
                if (_TextPro == null) _TextPro = GetComponent<TextMeshProUGUI>();
                return _TextPro;
            }
        }

        protected override BindDataType bindDataType => BindDataType.String;

        private void CheckLanguage()
        {
            // if (debug) Debug.LogErrorFormat("Text CheckLanguage");
            if (_language != Localization.Instance.language)
            {
                _language = Localization.Instance.language;
                _s = null;
                UpdateLocal();
            }
        }

        public override void SetData(JSONObject json)
        {
            CheckLanguage();
            if (!disabledKey.IsEmpty())
            {
                disabled = invert ? !disabledKey.Get(json).AsBool : disabledKey.Get(json).AsBool;
                if (disabled)
                    Disabled();
                else
                    Enabled();
            }

            base.SetData(json);
        }

        protected override void BindData(string s)
        {
            // if (debug) Debug.LogErrorFormat("Text BindData");
            CheckLanguage();
            if (s == null) s = "";
            UpdateText(s);
        }

        private void UpdateText(string s)
        {
            if (_s != null && _s.Equals(s)) return;
            _s = s;
            var text = GetText(s);
            if (textExtend != null) textExtend.useUnderline = false;
            if (StringTools.IsEmpty(text))
            {
                if (textExtend != null && underlineType == UnderlineType.Always) textExtend.useUnderline = true;
                if (!StringTools.IsEmpty(placeholder)) text = GetPlaceholder(placeholder);
                SetText(text);
            }
            else
            {
                if (textExtend != null && underlineType != UnderlineType.None) textExtend.useUnderline = true;
                SetText(StringTools.IsEmpty(format) ? text : string.Format(GetFormat(format), text));
            }
        }

        private string GetText(string s)
        {
            // Debug.LogErrorFormat("{0} {1} {2}", gameObject.name, gameObject.transform.parent.name ,s);
            if (local && !StringTools.IsEmpty(s))
            {
                var l = Localization.Instance.GetLocalValue(s);
                s = l == "" ? s : l;
            }
            if (online && !StringTools.IsEmpty(s))
            {
                var o = Localization.Instance.GetOnlineValue(s);
                // Debug.LogErrorFormat("GetText: {0} {1}", s, o);
                s = o == "" ? s : o;
            }

            return s;
        }

        private string GetFormat(string s)
        {
            // Debug.LogErrorFormat("{0} {1} {2}", gameObject.name, gameObject.transform.parent.name ,s);
            if (formatOnline && !StringTools.IsEmpty(s))
            {
                var o = Localization.Instance.GetOnlineValue(s);
                s = o == "" ? s : o;
            }

            return s;
        }

        private string GetPlaceholder(string s)
        {
            // Debug.LogErrorFormat("{0} {1} {2}", gameObject.name, gameObject.transform.parent.name ,s);
            if (placeholderOnline && !StringTools.IsEmpty(s))
            {
                var o = Localization.Instance.GetOnlineValue(s);
                s = o == "" ? s : o;
            }

            return s;
        }

        private void SetText(string t)
        {
            if (pro)
                TextPro.text = t;
            else
                Text.text = t;
            
            Refresh();
        }

        private void SetColor(Color c)
        {
            if (pro)
                TextPro.color = c;
            else
                Text.color = c;
        }

        protected override void BindData(bool b)
        {
            CheckLanguage();
            if (b)
                Enabled();
            else
                Disabled();
        }

        private void Disabled()
        {
            disabled = true;
            SetColor(disableColor);
            if (disableText != "") UpdateText(disableText);
        }

        private void Enabled()
        {
            disabled = false;
            SetColor(originColor);
            if (originText != "") UpdateText(originText);
        }

        private float GetWidth(Text text)
        {
            var tg = text.cachedTextGeneratorForLayout;
            var settings = text.GetGenerationSettings(Vector2.zero);
            return tg.GetPreferredWidth(text.text, settings) / text.pixelsPerUnit;
        }

        private float GetWidth(TextMeshProUGUI text)
        {
            return text.preferredWidth;
        }

        public float GetWidth()
        {
            if (pro)
                return GetWidth(TextPro);
            return GetWidth(Text);
        }

        private float GetHeight(Text text)
        {
            var tg = text.cachedTextGeneratorForLayout;
            var settings = text.GetGenerationSettings(Vector2.zero);
            return tg.GetPreferredHeight("0", settings) / text.pixelsPerUnit / (text.lineSpacing + 1);
        }

        private float GetHeight(TextMeshProUGUI text)
        {
            return text.preferredHeight / (text.lineSpacing + 1);
        }

        public float GetHeight()
        {
            if (pro)
                return GetHeight(TextPro);
            return GetHeight(Text);
        }

        [Button]
        public void UpdateLocal()
        {
            if (localText == "") return;
            // if (debug) Debug.LogErrorFormat("Text UpdateLocal: {0}", localText);
            UpdateText(localText);
        }

        [Button]
        public void Auto()
        {
            var width = GetWidth();
            var height = GetHeight();
            if (wrap)
            {
                var w = rectTransform.rect.width;
                var line = width > w ? (int)Math.Ceiling(width / w) : 1;
                height *= line;
                width = w;
            }

            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, width);
            rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
        }

        [Button]
        public void Refresh()
        {
            if (auto) Auto();
            if (textExtend != null) textExtend.Refresh();
            if (adaptiveSize != null) adaptiveSize.Refresh();
        }

        [Button]
        public void SaveLocalByOnline()
        {
            if (Text.text != "")
            {
                localText = Text.text;
                online = true;
            }
        }
    }
}